//
//  CalcTree2.c
//  抽象二叉树
//
//  Created by chenyh on 2021/1/27.
//
#include <stdlib.h>
#include "CalcTree2.h"
/**虚函数表*/
typedef double (*node_calc_t)(Node *pThis);
typedef void (*node_cleanup_t)(Node *pThis);
struct _NodeVTable {
    const node_calc_t node_calc;
    const node_cleanup_t node_cleanup;
};

static double _numnode_calc(Node *pThis)
{
    printf("numeric node%lf\n",((NumNode *)pThis)->_num);
    return ((NumNode *)pThis)->_num;
}
static void _numnode_cleanup(Node *pThis)
{
    printf("NumNode cleanup\n");
    free(pThis);
}

const NodeVTable _numnode_vtable = {_numnode_calc,_numnode_cleanup};

static void _binnode_cleanup(Node *pThis)
{
    printf("BinNode cleanup\n");
    BinNode *pBinNode = (BinNode *)pThis;
    node_cleanup(pBinNode->p_Left);
    node_cleanup(pBinNode->p_Right);
    free(pThis);
}
static double _addnode_calc(Node *pThis)
{
    printf("Adding...\n");

    AddNode *pAddNode = (AddNode *)pThis;
    return node_calc(pAddNode->_pLeft) + node_calc(pAddNode->_pRight);
}

const NodeVTable _addnode_vtable = {_addnode_calc,_binnode_cleanup};

static double _multnode_calc(Node *pThis)
{
    printf("Adding...\n");

    MultNode *pMultNode = (MultNode *)pThis;
    return node_calc(pMultNode->_pLeft) + node_calc(pMultNode->_pRight);
}

const NodeVTable _multnode_vtable = {_multnode_calc,_binnode_cleanup};

NumNode * newNumNode(double num)
{
    NumNode *node = malloc(sizeof(NumNode));
    if (node != NULL) {
        node->isa.vtable = &_numnode_vtable;
        node->_num = num;
    }
    return node;
}
AddNode * newAddNode(Node *pLeft,Node *pRight)
{
    AddNode *node = malloc(sizeof(AddNode));
    if (node != NULL) {
        node->isa.vtable = &_addnode_vtable;
        
        node->_pLeft = pLeft;
        node->_pRight = pRight;
    }
    return node;
}

MultNode * newMulNode(Node *pLeft,Node *pRight)
{
    MultNode *node = malloc(sizeof(MultNode));
    if (node != NULL) {
        node->isa.vtable = &_multnode_vtable;
        node->_pLeft = pLeft;
        node->_pRight = pRight;
    }
    return node;
}
double node_calc(Node *pThis)
{
    return pThis->vtable->node_calc(pThis);
}
void node_cleanup(Node *pThis)
{
    pThis->vtable->node_cleanup(pThis);
}
